package org.androidactiverecord;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

/**
 * A helpful class for displaying AREntities in a list.
 * 
 * @author jeremyot
 * 
 * @param <T>
 *            The type of the entities to display.
 */
public class ARListAdapter<T extends AREntity> extends ArrayAdapter<T> {

	private final Class<T> type;
	private String column = null;
	private String value = null;
	private String whereClause = null;
	private String[] whereArgs = null;
	private String orderBy = null;
	private int viewResourceID = 0;
	private Map<String, Integer> textViewMap;

	/**
	 * Create a new adapter for the specified type.
	 * 
	 * @param type
	 *            Any AREntity class.
	 * @param context
	 *            The application context.
	 * @param textViewResourceID
	 *            The resource ID of a text view to use for display.
	 */
	public ARListAdapter(Class<T> type, Context context, int textViewResourceID) {
		super(context, textViewResourceID);
		this.type = type;
	}

	/**
	 * Create a new adapter for the specified type.
	 * 
	 * @param type
	 *            Any AREntity class.
	 * @param context
	 *            The application context.
	 * @param resourceID
	 *            The resource ID of a view to use for display.
	 * @param textViewIDColumnMapping
	 *            A String-Integer map of column names to field IDs to use for display.
	 */
	public ARListAdapter(Class<T> type, Context context, int resourceID,
			Map<String, Integer> textViewIDColumnMapping) {
		super(context, resourceID);
		textViewMap = textViewIDColumnMapping;
		this.type = type;
		viewResourceID = resourceID;
	}

	/**
	 * Create a new adapter for the specified type.
	 * 
	 * @param type
	 *            Any AREntity class.
	 * @param context
	 *            The application context.
	 * @param resourceID
	 *            The resource ID of a view to use for display.
	 * @param textViewResourceID
	 *            The ID of the text view to use for display.
	 */
	public ARListAdapter(Class<T> type, Context context, int resourceID, int textViewResourceID) {
		super(context, resourceID, textViewResourceID);
		this.type = type;
	}

	/**
	 * Set a column restriction for entities to display (example: hidden,false)
	 * 
	 * @param column
	 *            The column to filter by.
	 * @param value
	 *            The value required for display.
	 */
	public void setColumnRestriction(String column, String value) {
		whereClause = null;
		whereArgs = null;
		this.column = column;
		this.value = value;
	}

	/**
	 * Set the column to order by, or null for the natural order.
	 * 
	 * @param orderBy
	 *            The column to order by.
	 */
	public void setOrderBy(String orderBy) {
		this.orderBy = orderBy;
	}

	/**
	 * Set a restriction for entities to display.
	 * 
	 * @param whereClause
	 *            The condition to match (don't include "where").
	 * @param whereArgs
	 *            The values to replace "?" with.
	 */
	public void setRestriction(String whereClause, String[] whereArgs) {
		column = null;
		value = null;
		this.whereClause = whereClause;
		this.whereArgs = whereArgs;
	}

	public void refreshAdapter() throws IllegalArgumentException, IllegalAccessException,
			InstantiationException {
		clear();
		if (column != null && value != null) {
			if (orderBy == null) {
				for (T item : AREntity.findByColumn(type, column, value))
					add(item);
			} else {
				for (T item : AREntity.find(type, false, String.format("%s = ?", column),
						new String[] { value }, orderBy, null))
					add(item);
			}
		} else if (whereClause != null) {
			if (orderBy == null) {
				for (T item : AREntity.find(type, whereClause, whereArgs))
					add(item);
			} else {
				for (T item : AREntity.find(type, false, whereClause, whereArgs, orderBy, null))
					add(item);
			}
		} else {
			for (T item : AREntity.findAll(type))
				add(item);
		}
		notifyDataSetChanged();
	}

	/**
	 * Get the item at the specified position.
	 * 
	 * @param position
	 *            The position to grab.
	 * @return The AREntity being displayed at the specified position.
	 */
	public T getARItem(int position) {
		return (T) getItem(position);
	}

	/**
	 * Get the id of the item at the specified position.
	 * 
	 * @param position
	 *            The position to grab.
	 * @return The ID of the AREntity being displayed at the specified position.
	 */
	public long getARItemId(int position) {
		return ((T) getItem(position))._id;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if (textViewMap == null)
			return super.getView(position, convertView, parent);
		View toRet = (convertView == null ? View.inflate(getContext(), viewResourceID, null) : convertView);
		T are = getARItem(position);
		List<Field> fields = are.getColumnFields();
		for (String s : textViewMap.keySet()) {
			Field match = null;
			for (Field f : fields) {
				if (f.getName().equals(s)) {
					match = f;
					break;
				}
			}
			if (match == null) {
				throw new IllegalArgumentException(String.format("No such field in AREntity class %s: %s.",
						are.getClass().getName(), s));
			}
			try {
				String text = String.valueOf(match.get(are));
				if (text == null || text.equals("None"))
					text = "";
				((TextView) toRet.findViewById(textViewMap.get(s).intValue())).setText(text);
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
		return toRet;
	}
}
